/**
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

package pittypat.web;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import pittypat.*;
import pittypat.configuration.ConfigException;
import pittypat.primitives.Uuid;

import java.beans.PropertyVetoException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.UUID;

/**
 * 处理新通知数目、通知列表、以及阅读通知。
 */
final class NotificationHandler {
	private NotificationHandler() {
	}

	/**
	 * 处理新通知数目、通知列表、以及阅读通知。
	 * 
	 * @param request
	 *            当前请求对象。
	 * @param response
	 *            当前响应对象。
	 * 
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws ClassNotFoundException
	 * @throws PropertyVetoException
	 * @throws ConfigException
	 * @throws SQLException
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @throws InvocationTargetException
	 * @throws IllegalArgumentException
	 */
	public static void handle(String path, HttpServletRequest request, HttpServletResponse response)
			throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, SQLException,
			ConfigException, PropertyVetoException {
		if (path.equalsIgnoreCase("/notification/count")) {
			// 查询当前用户的新通知计数
			processCount(request, response);
		} else if (path.equalsIgnoreCase("/notification/list")) {
			// 查询当前用户的新通知列表
			processList(request, response);
		} else if (path.equalsIgnoreCase("/notification/read")) {
			// 将当前用户指定的新通知标记为已读
			processRead(request, response);
		} else {
			// 不支持的其他请求路径
			response.sendError(404, "Not Found");
		}
	}

	/**
	 * 处理查询当前用户的新通知计数的请求。
	 * 
	 * @param request
	 *            当前请求对象。
	 * @param response
	 *            当前响应对象。
	 * 
	 * @throws IOException
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 * @throws SQLException
	 * @throws ConfigException
	 * @throws PropertyVetoException
	 */
	private static void processCount(HttpServletRequest request, HttpServletResponse response)
			throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, SQLException,
			ConfigException, PropertyVetoException {
		// 当前通知服务
		INotificationService notificationService = NotificationService.getCurrent();

		if (notificationService == null) {
			// 配置文件中没有配置通知服务
			ResponseHelper.sendErrorMessage(response,
					"没有提供有效的通知中心服务，请检查配置文件的 notificationService 配置项目。\r\n这是一个配置错误，需要系统管理人员调整配置文件。");
			return;
		}

		// 获取用户资料，因为不是对某个功能的请求，因此这里不进行权限检查。但是如果用户尚未登录，则需要拒绝用户。
		IUser user = RequestContext.getUser(RequestContext.getRequestContext(request).getUserToken());

		if (user.getId() == null) {
			// 匿名用户不能访问通知服务
			ResponseHelper.sendErrorMessage(response,
					String.format("用户未登录或会话已经过期，没有权限访问 %s。\r\n请重新登录。", request.getRequestURI()));
			return;
		}

		// 查询新通知数目
		long count = notificationService.count(user.getId(), WebAsyncProgress.DEFAULT);
		// 发送新通知数目
		ResponseHelper.sendValueMessage(response, Json.from(count < 0 ? 0 : count));
	}

	/**
	 * 处理查询当前用户的新通知列表的请求。
	 * 
	 * @param request
	 *            当前请求对象。
	 * @param response
	 *            当前响应对象。
	 * 
	 * @throws IOException
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 * @throws SQLException
	 * @throws ConfigException
	 * @throws PropertyVetoException
	 */
	private static void processList(HttpServletRequest request, HttpServletResponse response)
			throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, SQLException,
			ConfigException, PropertyVetoException {
		// 当前通知服务
		INotificationService notificationService = NotificationService.getCurrent();

		if (notificationService == null) {
			// 配置文件中没有配置通知服务
			ResponseHelper.sendErrorMessage(response,
					"没有提供有效的通知中心服务，请检查配置文件的 notificationService 配置项目。\r\n这是一个配置错误，需要系统管理人员调整配置文件。");
			return;
		}

		// 获取用户资料，因为不是对某个功能的请求，因此这里不进行权限检查。但是如果用户尚未登录，则需要拒绝用户。
		IUser user = RequestContext.getUser(RequestContext.getRequestContext(request).getUserToken());

		if (user.getId() == null) {
			// 匿名用户不能访问通知服务
			ResponseHelper.sendErrorMessage(response,
					String.format("用户未登录或会话已经过期，没有权限访问 %s。\r\n请重新登录。", request.getRequestURI()));
			return;
		}

		// 查询新通知列表
		NotificationList list = notificationService.list(user.getId(), WebAsyncProgress.DEFAULT);
		// 发送新通知列表
		ResponseHelper.sendValueMessage(response, list == null ? NotificationList.EMPTY : list);
	}

	/**
	 * 处理将当前用户指定的新通知标记为已读的请求。
	 * 
	 * @param request
	 *            当前请求对象。
	 * @param response
	 *            当前响应对象。
	 * 
	 * @throws IOException
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 * @throws SQLException
	 * @throws ConfigException
	 * @throws PropertyVetoException
	 */
	private static void processRead(HttpServletRequest request, HttpServletResponse response)
			throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, SQLException,
			ConfigException, PropertyVetoException {
		// 当前通知服务
		INotificationService notificationService = NotificationService.getCurrent();

		if (notificationService == null) {
			// 配置文件中没有配置通知服务
			ResponseHelper.sendErrorMessage(response,
					"没有提供有效的通知中心服务，请检查配置文件的 notificationService 配置项目。\r\n这是一个配置错误，需要系统管理人员调整配置文件。");
			return;
		}

		// 获取用户资料，因为不是对某个功能的请求，因此这里不进行权限检查。但是如果用户尚未登录，则需要拒绝用户。
		IUser user = RequestContext.getUser(RequestContext.getRequestContext(request).getUserToken());

		if (user.getId() == null) {
			// 匿名用户不能访问通知服务
			ResponseHelper.sendErrorMessage(response,
					String.format("用户未登录或会话已经过期，没有权限访问 %s。\r\n请重新登录。", request.getRequestURI()));
			return;
		}

		// 要标记为已读的通知消息的 Id
		String sid = request.getParameter("id");

		if (sid != null && sid.length() > 0) {
			// 将字符串转换为 UUID
			UUID uuid = null;
			try {
				uuid = Uuid.parse(sid);
			} catch (Exception e) {
				uuid = null;
			}

			if (uuid != null) {
				// 将消息标记为已读，并且返回标记时间
				LocalDateTime readTime = notificationService.read(user.getId(), uuid, WebAsyncProgress.DEFAULT);
				// 发送标记时间
				ResponseHelper.sendValueMessage(response, Json.from(readTime));
				return;
			}
		}

		// 没有提供有效的 Id
		ResponseHelper.sendErrorMessage(response, "没有提供要标记为已读的消息的 Id。\r\n这是一个编码错误，需要开发人员提交必要的参数。");
	}
}
